<template>
    <div id="mapBoxId"></div>
    <div class="option-btn__list">
        <button class="btn-item" @click="start">开始</button>
        <button class="btn-item" @click="stop">暂停</button>
    </div>
</template>
<script lang="ts" setup>
import { TDMAP_TK } from '@/utils/constant';
import { Feature, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import { fromLonLat } from 'ol/proj';
import { XYZ } from 'ol/source';
import MapType from 'ol/Map.js';
import { defaults as defaultControls } from 'ol/control';

import Style from 'ol/style/Style';
import Icon from 'ol/style/Icon';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Stroke from 'ol/style/Stroke';
import LineString from 'ol/geom/LineString';
import Point from 'ol/geom/Point';
let map: MapType;
let markerSource: VectorSource;
const lineArr: Array<[number, number]> = [
    [116.478935, 39.997761],
    [116.478939, 39.997825],
    [116.478912, 39.998549],
    [116.478912, 39.998549],
    [116.478998, 39.998555],
    [116.478998, 39.998555],
    [116.479282, 39.99856],
    [116.479658, 39.998528],
    [116.480151, 39.998453],
    [116.480784, 39.998302],
    [116.480784, 39.998302],
    [116.481149, 39.998184],
    [116.481573, 39.997997],
    [116.481863, 39.997846],
    [116.482072, 39.997718],
    [116.482362, 39.997718],
    [116.483633, 39.998935],
    [116.48367, 39.998968],
    [116.484648, 39.999861]
];

let carIcon: any;
const carImg = new URL('@/assets/img/car.png', import.meta.url).href;
/**
 * 图层
 */
const getLayers = () => {
    // 天地图矢量图层
    const tdMapVectorLayer = new TileLayer({
        zIndex: 30,
        className: 'tdVector',
        visible: true,
        source: new XYZ({
            url: `https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${TDMAP_TK}`,
            wrapX: false
        })
    });
    // 天地图标注层
    const tdMapCvaLayer = new TileLayer({
        zIndex: 31,
        className: 'tdCva',
        visible: true,
        source: new XYZ({
            url: `https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${TDMAP_TK}`,
            wrapX: false
        })
    });
    const routeCoords = lineArr.map(item => fromLonLat(item));
    const lineFeature = new Feature({
        geometry: new LineString(routeCoords)
    });
    const routeLayer = new VectorLayer({
        zIndex: 32,
        className: 'route',
        visible: true,
        source: new VectorSource({
            features: [lineFeature]
        }),
        style: new Style({
            stroke: new Stroke({
                color: '#28F',
                width: 6
            })
        })
    });
    carIcon = new Feature({
        geometry: new Point(fromLonLat([116.478935, 39.997761]))
    });
    carIcon.setStyle(
        new Style({
            image: new Icon({
                src: carImg,
                scale: 1,
                rotation: 0, // 初始角度,
                anchor: [0.5, 0.5],
                rotateWithView: true
            })
        })
    );
    markerSource = new VectorSource({
        features: [carIcon]
    });
    const markerLayer = new VectorLayer({
        zIndex: 33,
        className: 'marker',
        visible: true,
        source: markerSource
    });
    const passedPolyline = new VectorLayer({
        zIndex: 33,
        className: 'passedPolyline',
        visible: true,
        source: new VectorSource({
            features: [
                new Feature({
                    geometry: new LineString([])
                })
            ]
        }),
        style: new Style({
            stroke: new Stroke({
                color: '#AF5',
                width: 6
            })
        })
    });

    const arrowsSource = new VectorSource();
    // 计算箭头位置和角度（每隔一段距离放一个箭头）
    const line = lineFeature.getGeometry()!;
    const length = line.getLength();
    const step = length / 10; // 每10%路径长度放一个箭头

    for (let i = 0; i < length; i += step) {
        const segment = line.getCoordinateAt(i / length);
        const segmentNext = line.getCoordinateAt(Math.min((i + 1) / length, 1));

        // 计算角度（弧度）
        const dx = segmentNext[0] - segment[0];
        const dy = segmentNext[1] - segment[1];
        const angle = Math.atan2(dy, dx);

        const arrow = new Feature({
            geometry: new Point(segment)
        });
        arrow.setStyle(
            new Style({
                image: new Icon({
                    src:
                        'data:image/svg+xml;utf8,' +
                        '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24">' +
                        '<path fill="white" d="M12 2L2 12l10 10 10-10z"/>' + // 更瘦长的三角形
                        '</svg>',
                    scale: 1,
                    rotation: angle, // 箭头方向跟随路径
                    rotateWithView: true, // 保持箭头方向与地图旋转同步,

                    anchor: [0.5, 0.5] // 中心锚点
                })
            })
        );
        arrowsSource.addFeature(arrow);
    }
    // 5. 添加方向箭头（三角形图标）
    const arrowsLayer = new VectorLayer({
        source: arrowsSource,
        zIndex: 33,
        visible: true,
        className: 'arrows'
    });
    const layers = [
        tdMapVectorLayer,
        tdMapCvaLayer,
        routeLayer,
        passedPolyline,
        arrowsLayer,
        markerLayer
    ];
    return layers;
};
/**
 * 初始化地图
 */
const initMap = () => {
    const layers = getLayers();
    const view = new View({
        center: fromLonLat([116.478935, 39.997761]),
        zoom: 17,
        minZoom: 9,
        constrainResolution: true, // 设置缩放级别为整数
        smoothResolutionConstraint: false // 关闭无级缩放地图
    });
    map = new MapType({
        target: 'mapBoxId',
        layers,
        view,
        controls: defaultControls({
            zoom: false,
            rotate: false,
            attribution: false
        })
    });
};

/**
 * 销毁左侧地图
 */
const distoryMap = () => {
    map && map.setTarget();
    map && map.dispose();
};
function interpolatePoints(
    start: [number, number],
    end: [number, number],
    steps: number
): Array<[number, number]> {
    const points: Array<[number, number]> = [];
    for (let i = 0; i <= steps; i++) {
        const ratio = i / steps;
        points.push([
            start[0] + (end[0] - start[0]) * ratio,
            start[1] + (end[1] - start[1]) * ratio
        ]);
    }
    return points;
}

let smoothTrack: Array<[number, number]>;
let currentIndex = 0;
const speed = 40;
let lastTimestamp = 0;
let paused = false;
let animationId: number;
let lastAngle = 0;
const angleSmoothingFactor = 0.2; // 角度平滑系数
const createDensePath = () => {
    smoothTrack = [];
    for (let i = 0; i < lineArr.length - 1; i++) {
        smoothTrack = smoothTrack.concat(interpolatePoints(lineArr[i], lineArr[i + 1], 50));
    }
};
// 带平滑的角度计算
function calculateSmoothedAngle(currentPoint: [number, number], nextPoint: [number, number]) {
    const dx = nextPoint[0] - currentPoint[0];
    const dy = nextPoint[1] - currentPoint[1];
    const newAngle =- Math.atan2(dy, dx) +Math.PI/2;;

    // // 角度平滑处理
    const angleDiff = ((newAngle - lastAngle + Math.PI) % (2 * Math.PI)) - Math.PI;
    const smoothedAngle = lastAngle + angleDiff * angleSmoothingFactor;
    lastAngle = smoothedAngle;
    return smoothedAngle;
}
// 更新小车样式函数
function updateCarStyle(position: [number, number], nextPosition: [number, number]) {
    // 计算方向角度
    const angle = calculateSmoothedAngle(position, nextPosition);
    carIcon.setStyle(
        new Style({
            image: new Icon({
                src: carImg,
                scale: 1,
                rotation: angle,
                anchor: [0.5, 0.5],
                rotateWithView: true
            })
        })
    );
}
const playSmoothTrack = () => {
    if (paused) return;

    const now = Date.now();
    const elapsed = lastTimestamp ? now - lastTimestamp : 0;
    lastTimestamp = now;
    // 计算移动步长（基于速度）
    const step = (speed * elapsed) / 1000;
    // 计算新的位置索引
    currentIndex = currentIndex + step;

    // 检查是否到达终点
    if (currentIndex >= smoothTrack.length - 1) {
        // 到达终点，停止移动
        carIcon.getGeometry().setCoordinates(fromLonLat(smoothTrack[smoothTrack.length - 1]));
        updateCarStyle(smoothTrack[smoothTrack.length - 2], smoothTrack[smoothTrack.length - 1]);
        clearTimeout(animationId);
        paused = true;
        return;
    }
    // 获取当前和下一个位置点
    const currentIdx = Math.floor(currentIndex);
    const nextIdx = currentIdx + 1;

    const currentPoint = smoothTrack[currentIdx];
    const nextPoint = smoothTrack[nextIdx];

    // 计算插值位置（使移动更平滑）
    const fraction = currentIndex - currentIdx;
    const interpolatedPoint: [number, number] = [
        currentPoint[0] + (nextPoint[0] - currentPoint[0]) * fraction,
        currentPoint[1] + (nextPoint[1] - currentPoint[1]) * fraction
    ];

    carIcon.getGeometry().setCoordinates(fromLonLat(interpolatedPoint));
    updateCarStyle(interpolatedPoint, nextPoint);
    map.getView().setCenter(fromLonLat(interpolatedPoint));
    animationId = requestAnimationFrame(playSmoothTrack); // 约60fps
};
// 重置小车位置
function resetCar() {
    currentIndex = 0;
    carIcon.getGeometry().setCoordinates(fromLonLat(smoothTrack[0]));
    updateCarStyle(smoothTrack[0], smoothTrack[1]);
}
const start = () => {
    paused = false;
    if (currentIndex >= smoothTrack.length - 1) {
        resetCar();
    }
    paused = false;
    lastTimestamp = Date.now();
    playSmoothTrack();
};
const stop = () => {
    paused = true;
    if (animationId) cancelAnimationFrame(animationId);
};
onMounted(() => {
    createDensePath();
    initMap();
});
onBeforeUnmount(() => {
    distoryMap();
});
</script>
<style lang="scss" scoped>
#mapBoxId {
    width: 100vw;
    height: 100vh;
}
.option-btn__list {
    position: fixed;
    right: 20px;
    top: 20px;
    display: flex;
    z-index: 99;
    gap: 10px;
    .btn-item {
        border: none;
        background-color: #1e71ff;
        border-radius: 20px;
        padding: 0 20px;
        text-align: center;
        color: #fff;
        height: 36px;
        line-height: 36px;
        cursor: pointer;
    }
}
</style>
